﻿using System;
using System.IO;
using State;
using Windows.UI.Popups;
using Windows.UI.Text;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
using Game;
using Windows.Storage;
using Windows.Storage.Streams;
using System.Text;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.UI.Xaml.Media.Imaging;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238

namespace TTT
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage
    {
        StorageFile _tttFile;
        const string FileName = "saveData.ttt";

        public MainPage()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Invoked when this page is about to be displayed in a Frame.
        /// </summary>
        /// <param name="e">Event data that describes how this page was reached.  The Parameter
        /// property is typically used to configure the page.</param>
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
        }

        /// <summary>
        /// This will handle the button being pressed and place
        /// either an X or an O depending on the current player
        /// </summary>
        /// <param name="sender">Button that has been clicked</param>
        /// <param name="e"></param>
        private async void HandleClick(object sender, RoutedEventArgs e)
        {
            var btn = (Button)sender;

            string s;
            switch (btn.Name)
            {
                case "One":
                    s = TttGame.UpdateTile(1);
                    break;
                case "Two":
                    s = TttGame.UpdateTile(2);
                    break;
                case "Three":
                    s = TttGame.UpdateTile(3);
                    break;
                case "Four":
                    s = TttGame.UpdateTile(4);
                    break;
                case "Five":
                    s = TttGame.UpdateTile(5);
                    break;
                case "Six":
                    s = TttGame.UpdateTile(6);
                    break;
                case "Seven":
                    s = TttGame.UpdateTile(7);
                    break;
                case "Eight":
                    s = TttGame.UpdateTile(8);
                    break;
                case "Nine":
                    s = TttGame.UpdateTile(9);
                    break;
                default:
                    s = "ERROR";
                    break;
            }
            
            var img = new Image
                {
                    Source =
                        s == "O"
                            ? new BitmapImage(new Uri(BaseUri, @"Assets/O.png"))
                            : new BitmapImage(new Uri(BaseUri, @"Assets/X.png"))
                };

            btn.Content = img;  

            btn.IsEnabled = false;
            
            var winRow = TttGame.CheckWin();
            UpdatePlayer();

            if ((winRow != null) && (winRow[0] == 0)) // no draw or win
                return;
           
            string winner;
            if (winRow == null)
                winner = "Draw Game!";
            else
            {
                winner = "Player " + TttState.WhoTurn + " Wins!";
                for (var i = 0; i <= 2; i++)
                {
                    var name = IntToName(winRow[i]);
                    Button b = null;
                    var j = 0;
                    do
                    {
                        if (Buttons.Items != null) b = (Button)Buttons.Items[j];
                        j++;
                    } while (b != null && (b.Name != name && (j <= 8)));

                    if (b != null)
                        b.Content = new Image
                            {
                                Source =
                                    s == "O"
                                        ? new BitmapImage(new Uri(BaseUri, @"Assets/Ow.png"))
                                        : new BitmapImage(new Uri(BaseUri, @"Assets/Xw.png"))
                            };
                }
            }
            var md = new MessageDialog("", winner);
            md.Commands.Add(new UICommand("Ok"));

            await md.ShowAsync();
            One.IsEnabled = false;
            Two.IsEnabled = false;
            Three.IsEnabled = false;
            Four.IsEnabled = false;
            Five.IsEnabled = false;
            Six.IsEnabled = false;
            Seven.IsEnabled = false;
            Eight.IsEnabled = false;
            Nine.IsEnabled = false;
            
        }

        /// <summary>
        /// This will handle the Reset Button being pressed
        /// </summary>
        /// <param name="sender">Button that has been pressed</param>
        /// <param name="e"></param>
        private void HandleReset(object sender, RoutedEventArgs e)
        {
            TttGame.Reset();
            UpdatePlayer();
            ResetBoard();
        }

        /// <summary>
        /// This will handle the Play Again Button being pressed
        /// </summary>
        /// <param name="sender">Button that has been pressed</param>
        /// <param name="e"></param>
        private void HandleAgain(object sender, RoutedEventArgs e)
        {
            TttGame.NewGame();
            UpdatePlayer();
            ResetBoard();
        }

        /// <summary>
        /// This will handle the Begin Button being pressed
        /// </summary>
        /// <param name="sender">Button that has been pressed</param>
        /// <param name="e"></param>
        private void Begin_Click(object sender, RoutedEventArgs e)
        {
            TttGame.Initialize();

            UpdatePlayer();

            Begin.IsEnabled = false;
            Begin.Visibility = Visibility.Collapsed;

            Buttons.Visibility = Visibility.Visible;
            Controls.IsEnabled = true;
        }

        /// <summary>
        /// This will swap which player is currently allowed to press
        /// a button.
        /// </summary>
        private void UpdatePlayer()
        {
            if (TttState.WhoTurn == PlayerTurn.O)
            {
                OLabel.FontStyle = FontStyle.Oblique;
                XLabel.FontStyle = FontStyle.Normal;
            }
            else
            {
                XLabel.FontStyle = FontStyle.Oblique;
                OLabel.FontStyle = FontStyle.Normal;
            }
            ScoreX.Text = TttGame.PlayerX.Score.ToString();
            ScoreO.Text = TttGame.PlayerO.Score.ToString();
        }

        /// <summary>
        /// This is the initialization after the Reset Button has
        /// been pressed.
        /// </summary>
        private void ResetBoard()
        {
            One.IsEnabled = true;
            Two.IsEnabled = true;
            Three.IsEnabled = true;
            Four.IsEnabled = true;
            Five.IsEnabled = true;
            Six.IsEnabled = true;
            Seven.IsEnabled = true;
            Eight.IsEnabled = true;
            Nine.IsEnabled = true;

            One.Content = "";
            Two.Content = "";
            Three.Content = "";
            Four.Content = "";
            Five.Content = "";
            Six.Content = "";
            Seven.Content = "";
            Eight.Content = "";
            Nine.Content = "";
        }

        /// <summary>
        /// This will handle te events that occur after the Save button has been pressed.
        /// </summary>
        /// <param name="sender">Button that has been pressed</param>
        /// <param name="e"></param>
        private async void HandleSave(object sender, RoutedEventArgs e)
        {
            var md = new MessageDialog("This will overwrite your previous save.", "Save Game?");
            bool? result = null;
            md.Commands.Add(new UICommand("Ok", cmd => result = true));
            md.Commands.Add(new UICommand("Cancel", cmd => result = false));

            await md.ShowAsync();

            if (result == false)
                return;

            var data = TttGame.GameState;
            if (String.IsNullOrEmpty(data))
            {
                md = new MessageDialog("","No game to save.");
                md.Commands.Add(new UICommand("Ok"));
                await md.ShowAsync();
            }
            else
            {
                var storageFolder = ApplicationData.Current.LocalFolder;
                _tttFile = await storageFolder.CreateFileAsync(FileName, CreationCollisionOption.ReplaceExisting);
                using (var sessionRandomAccess =
                        await _tttFile.OpenAsync(FileAccessMode.ReadWrite))
                {
                    var stream = sessionRandomAccess.AsStreamForWrite();
                    var array = Encoding.UTF8.GetBytes(data);
                    stream.SetLength(array.Length);

                    await stream.WriteAsync(array, 0, array.Length);
                    await stream.FlushAsync();

                    await sessionRandomAccess.FlushAsync();
                }
            }
        }

        /// <summary>
        /// Takes the passed in Integer and turns it as a string
        /// </summary>
        /// <param name="number">The passed in Interger</param>
        /// <returns>The passed in Integer as a string</returns>
        private static string IntToName(int number)
        {
            switch (number)
            {
                case 1:
                    return "One";
                case 2:
                    return "Two";
                case 3:
                    return "Three";
                case 4:
                    return "Four";
                case 5:
                    return "Five";
                case 6:
                    return "Six";
                case 7:
                    return "Seven";
                case 8:
                    return "Eight";
                case 9:
                    return "Nine";
                default:
                    return "ERROR";
            }
        }

        /// <summary>
        /// This will handle the events that occur after the Load button has
        /// been pressed.
        /// </summary>
        /// <param name="sender">Button that has been pressed</param>
        /// <param name="e"></param>
        private async void HandleLoad(object sender, RoutedEventArgs e)
        {
            var md = new MessageDialog("This will overwrite your current game.", "Load Game?");
            bool? result = null;
            md.Commands.Add(new UICommand("Ok", cmd => result = true));
            md.Commands.Add(new UICommand("Cancel", cmd => result = false));

            await md.ShowAsync();

            if (result == false)
                return;

            if (Begin.Visibility != Visibility.Collapsed)
                Begin_Click(sender, e);
            
            var success = false;
            try
            {
                if (_tttFile == null)
                {
                    var storageFolder = ApplicationData.Current.LocalFolder;
                    _tttFile = await storageFolder.GetFileAsync(FileName);
                }
                if (_tttFile != null)
                {
                    using (var sessionRandomAccess =
                        await _tttFile.OpenAsync(FileAccessMode.Read))
                    {
                        if (sessionRandomAccess.Size > 0)
                        {
                            var array3 = new byte[sessionRandomAccess.Size];
                            var output = await
                                        sessionRandomAccess.ReadAsync(
                                            array3.AsBuffer(0, (int)sessionRandomAccess.Size),
                                            (uint)sessionRandomAccess.Size,
                                            InputStreamOptions.Partial);
                            var gameData = Encoding.UTF8.GetString(output.ToArray(), 0, (int)output.Length);
                            TttGame.GameState = gameData;
                            var boardData = gameData.Substring(2, 9);
                            
                            for (var i = 0; i <= 8; i++)
                            {
                                var name = IntToName(i+1);
                               
                                var c = boardData[i];
                                if (Buttons.Items == null) continue;
                                // we must do this loop to make sure the correct button is being selected.
                                // Buttons.Items may not be in the correct order
                                Button b;
                                var k = 0;
                                do
                                {
                                    b = (Button)Buttons.Items[k];
                                    k++;
                                } while ((b.Name != name) && (k <= 8));
                                Image img;
                                switch (c)
                                {
                                    case '0':
                                        b.Content = "";
                                        b.IsEnabled = true;
                                        break;
                                    case '1':
                                        img = new Image {Source = new BitmapImage(new Uri(BaseUri, @"Assets/X.png"))};
                                        b.Content = img;
                                        b.IsEnabled = false;
                                        break;
                                    case '2':
                                        img = new Image {Source = new BitmapImage(new Uri(BaseUri, @"Assets/O.png"))};
                                        b.Content = img;
                                        b.IsEnabled = false;
                                        break;
                                }
                            }
                            UpdatePlayer();
                            success = true;
                        }
                    }
                }
            }
            catch (FileNotFoundException)
            {
                success = false;
            }

            if (success) return;
            md = new MessageDialog("", "ERROR: No game to load!");
            md.Commands.Add(new UICommand("Ok"));
            await md.ShowAsync();
        }
    }
}
